package com.cxx.food.util;

import cn.hutool.core.io.file.FileNameUtil;
import com.cxx.food.dto.file.ChunkInfoDto;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @Author: chenxiuxiang
 * @Date: 2023/7/24 14:49
 * @Description: 上传文件工具类
 */
@Slf4j
public class UploadFileUtil {
    private static final String FILE_SEPARATOR = "_";

    /**
     * 校验文件夹是否存在
     *
     * @param path 路径
     */
    public static void checkDirIsExist(String path) {
        File dir = new File(path);
        if (!dir.exists() && !dir.isDirectory()) {
            boolean mkdir = dir.mkdirs();
        }
    }

    /**
     * 获取文件路径
     *
     * @param path      上传文件夹路径
     * @param chunkInfo 分片文件信息
     * @return 文件路径
     */
    public static String generateChunkPath(String path, ChunkInfoDto chunkInfo) {
        return path + File.separator + chunkInfo.getFilename() + FILE_SEPARATOR + chunkInfo.getChunkNumber();
    }

    public static List<Integer> getUploadedChunkList(String folder, String filename) {
        List<Integer> uploadedChunkList = new ArrayList<>();

        // 获取文件夹下所有的文件
        try (Stream<Path> list = Files.list(Paths.get(folder))) {
            // 去除需要合并的文件
            list.filter(path -> !path.getFileName().toString().equals(filename))
                    // 循环遍历文件 将已经上传的文件序号添加至列表中
                    .forEach(path -> {
                        String chunkPath = path.getFileName().toString();
                        int index = chunkPath.lastIndexOf(FILE_SEPARATOR);
                        uploadedChunkList.add(Integer.valueOf(chunkPath.substring(index + 1)));
                    });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return uploadedChunkList;
    }

    /**
     * 文件合并
     */
    public static void mergeFile(String filename, String path) throws IOException {
        // 判断文件是否存在
        String file = path + File.separator + filename;
        if (fileExists(file)) {
            deleteFile(file);
        }

        // 不存在的话，进行合并
        Files.createFile(Paths.get(file));

        // 获取文件夹下所有的文件
        try (Stream<Path> list = Files.list(Paths.get(path))) {
            // 保留后缀包含分隔符的
            list.filter(chunkPath -> FileNameUtil.getSuffix(chunkPath.getFileName().toString()).contains(FILE_SEPARATOR))
                    // 按照文件名排序
                    .sorted((o1, o2) -> {
                        String p1 = o1.getFileName().toString();
                        String p2 = o2.getFileName().toString();
                        int i1 = p1.lastIndexOf(FILE_SEPARATOR);
                        int i2 = p2.lastIndexOf(FILE_SEPARATOR);
                        return Integer.valueOf(p1.substring(i1 + 1))
                                .compareTo(Integer.valueOf(p2.substring(i2 + 1)));
                    })
                    // 循环写入到文件中
                    .forEach(chunkPath -> {
                        try {
                            // 以追加的形式写入文件
                            Files.write(Paths.get(file), Files.readAllBytes(chunkPath), StandardOpenOption.APPEND);
                            // 合并后删除该块
                            Files.delete(chunkPath);
                        } catch (IOException exception) {
                            log.error("写入文件失败: " + exception.getMessage());
                            throw new RuntimeException(exception);
                        }
                    });
        }
    }

    /**
     * 根据文件的全路径名判断文件是否存在
     */
    public static boolean fileExists(String file) {
        Path path = Paths.get(file);
        return Files.exists(path, LinkOption.NOFOLLOW_LINKS);
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param sPath 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String sPath) {
        // 如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }

        boolean flag = true;
        // 删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (File file : Objects.requireNonNull(files)) {
            // 删除子文件
            if (file.isFile()) {
                flag = deleteFile(file.getAbsolutePath());
            }
            // 删除子目录
            else {
                flag = deleteDirectory(file.getAbsolutePath());
            }
            if (!flag) {
                break;
            }
        }
        if (!flag) {
            return false;
        }

        log.info("文件删除成功");
        // 删除当前目录
        return dirFile.delete();
    }

    /**
     * 删除单个文件
     *
     * @param sPath 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            flag = file.delete();
        }
        return flag;
    }
}